`async fn(HttpRequest) -> Result`
# Overview
tower-http is a library that provides HTTP-specific middleware and utilities built on top of
[tower].
All middleware uses the [http] and [http-body] crates as the HTTP abstractions. That means
they're compatible with any library or framework that also uses those crates, such as
[hyper], [tonic], and [warp].
# Example server
This example shows how to apply middleware from tower-http to a [`Service`] and then run
that service using [hyper].
```rust,no_run
use tower_http::{
add_extension::AddExtensionLayer,
compression::CompressionLayer,
propagate_header::PropagateHeaderLayer,
auth::RequireAuthorizationLayer,
sensitive_headers::SetSensitiveRequestHeadersLayer,
set_header::SetResponseHeaderLayer,
trace::TraceLayer,
};
use tower::{ServiceBuilder, service_fn, make::Shared};
use http::{Request, Response, header::{HeaderName, CONTENT_TYPE, AUTHORIZATION}};
use hyper::{Body, Error, server::Server, service::make_service_fn};
use std::{sync::Arc, net::SocketAddr, convert::Infallible, iter::once};
# struct DatabaseConnectionPool;
# impl DatabaseConnectionPool {
# fn new() -> DatabaseConnectionPool { DatabaseConnectionPool }
# }
# fn content_length_from_response(_: &http::Response) -> Option { None }
# async fn update_in_flight_requests_metric(count: usize) {}
// Our request handler. This is where we would implement the application logic
// for responding to HTTP requests...
async fn handler(request: Request) -> Result, Error> {
// ...
# todo!()
}
// Shared state across all request handlers --- in this case, a pool of database connections.
struct State {
pool: DatabaseConnectionPool,
}
#[tokio::main]
async fn main() {
// Construct the shared state.
let state = State {
pool: DatabaseConnectionPool::new(),
};
// Use tower's `ServiceBuilder` API to build a stack of tower middleware
// wrapping our request handler.
let service = ServiceBuilder::new()
// Mark the `Authorization` request header as sensitive so it doesn't show in logs
.layer(SetSensitiveRequestHeadersLayer::new(once(AUTHORIZATION)))
// High level logging of requests and responses
.layer(TraceLayer::new_for_http())
// Share an `Arc` with all requests
.layer(AddExtensionLayer::new(Arc::new(state)))
// Compress responses
.layer(CompressionLayer::new())
// Propagate `X-Request-Id`s from requests to responses
.layer(PropagateHeaderLayer::new(HeaderName::from_static("x-request-id")))
// If the response has a known size set the `Content-Length` header
.layer(SetResponseHeaderLayer::overriding(CONTENT_TYPE, content_length_from_response))
// Authorize requests using a token
.layer(RequireAuthorizationLayer::bearer("passwordlol"))
// Wrap a `Service` in our middleware stack
.service_fn(handler);
// And run our service using `hyper`
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
Server::bind(&addr)
.serve(Shared::new(service))
.await
.expect("server error");
}
```
Keep in mind that while this example uses [hyper], tower-http supports any HTTP
client/server implementation that uses the [http] and [http-body] crates.
# Example client
tower-http middleware can also be applied to HTTP clients:
```rust,no_run
use tower_http::{
decompression::DecompressionLayer,
set_header::SetRequestHeaderLayer,
trace::TraceLayer,
classify::StatusInRangeAsFailures,
};
use tower::{ServiceBuilder, Service, ServiceExt};
use hyper::Body;
use http::{Request, HeaderValue, header::USER_AGENT};
#[tokio::main]
async fn main() {
let mut client = ServiceBuilder::new()
// Add tracing and consider server errors and client
// errors as failures.
.layer(TraceLayer::new(
StatusInRangeAsFailures::new(400..=599).into_make_classifier()
))
// Set a `User-Agent` header on all requests.
.layer(SetRequestHeaderLayer::overriding(
USER_AGENT,
HeaderValue::from_static("tower-http demo")
))
// Decompress response bodies
.layer(DecompressionLayer::new())
// Wrap a `hyper::Client` in our middleware stack.
// This is possible because `hyper::Client` implements
// `tower::Service`.
.service(hyper::Client::new());
// Make a request
let request = Request::builder()
.uri("http://example.com")
.body(Body::empty())
.unwrap();
let response = client
.ready()
.await
.unwrap()
.call(request)
.await
.unwrap();
}
```
# Feature Flags
All middleware are disabled by default and can be enabled using [cargo features].
For example, to enable the [`Trace`] middleware, add the "trace" feature flag in
your `Cargo.toml`:
```toml
tower-http = { version = "0.1", features = ["trace"] }
```
You can use `"full"` to enable everything:
```toml
tower-http = { version = "0.1", features = ["full"] }
```
# Getting Help
If you're new to tower its [guides] might help. In the tower-http repo we also have a [number
of examples][examples] showing how to put everything together. You're also welcome to ask in
the [`#tower` Discord channel][chat] or open an [issue] with your question.
[tower]: https://crates.io/crates/tower
[http]: https://crates.io/crates/http
[http-body]: https://crates.io/crates/http-body
[hyper]: https://crates.io/crates/hyper
[guides]: https://github.com/tower-rs/tower/tree/master/guides
[tonic]: https://crates.io/crates/tonic
[warp]: https://crates.io/crates/warp
[cargo features]: https://doc.rust-lang.org/cargo/reference/features.html
[`AddExtension`]: crate::add_extension::AddExtension
[`Service`]: https://docs.rs/tower/latest/tower/trait.Service.html
[chat]: https://discord.gg/tokio
[issue]: https://github.com/tower-rs/tower-http/issues/new
[`Trace`]: crate::trace::Trace
[examples]: https://github.com/tower-rs/tower-http/tree/master/examples